package com.gcloud.mesh.sm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Stream;

import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.util.sm.SmKeyCode;
import org.jeecg.common.util.sm.SmManager;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;

import com.gcloud.mesh.header.exception.BaseException;

import lombok.extern.slf4j.Slf4j;

@Component
@DependsOn("passwordPropertyListener")
@Slf4j
public class DatabasePropertiesListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
	
	private static final String AUTH = "password";
	
    private static Map<String, String> keyMap = new HashMap<String, String>();

    static {
    	keyMap.put("spring.datasource.dynamic.datasource.master.password", null);
    	keyMap.put("mesh.data-security.password", null);
    	keyMap.put("mesh.data-classification.password", null);
    }

	public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
//		String  key = "5ec863eb9a4c37e11c87c7ed85ecd3d3";
		ConfigurableEnvironment environment = event.getEnvironment();
        MutablePropertySources  sources     = environment.getPropertySources();
        sources.forEach(source -> {
            PropertySource propertySource = sources.get(source.getName());
            if (propertySource instanceof OriginTrackedMapPropertySource) {
                //保存处理过后的值
                Map<String, Object> convertPropertySource = new HashMap<>();
                //重新定义一个PropertySource，覆盖原来的
                OriginTrackedMapPropertySource newMapPropertySource = new OriginTrackedMapPropertySource(propertySource.getName(),
                                                                               convertPropertySource);
                String[] propertyNames = ((MapPropertySource) propertySource).getPropertyNames();
                Stream.of(propertyNames).forEach(name -> {
                	
                    Object value = propertySource.getProperty(name);
                    if (value instanceof String) {                       
                        if(keyMap.containsKey(name)) {
                        	String originalValue = (String) value;
                        	log.info("properties:"+String.valueOf(propertySource.getName()));
                        	log.info(name+" database--oldpassword--is"+originalValue);
                        	String newValue = decrpyt(name, SmKeyCode.CONFIG_AUTH_SM_KEY, originalValue);
                        	if(newValue != null) {
                        		log.info("database--password--is"+String.valueOf(newValue));
                            	convertPropertySource.put(name, newValue);
                            	keyMap.put(name, newValue);
                        	}
                        	
                        } else {
                            convertPropertySource.put(name, value);
                        }
                    } else {
                        convertPropertySource.put(name, value);
                    }
                });
                //处理过后值替换原来的PropertySource
                sources.replace(source.getName(), newMapPropertySource);
                
            }
        });

    }
	
	private String decrpyt(String name, String key, String cipher) {
		String value = null;
		try {					
			String data = SmManager.decryptClientSm4(SmKeyCode.CONFIG_AUTH_SM_KEY, cipher);
			if(data != null && data.length() > 64) {
				int len = data.length();
				String sm3Key = data.substring(len-64, len);
				String smData = data.substring(0, len-64);
				if(SmManager.verifySm3(smData, sm3Key)) {
					log.info("[DatabasePropertiesListener][onApplicationEvent] {}【{}】数据完整性校验成功", name, cipher);	
				}else {
					log.info("[DatabasePropertiesListener][onApplicationEvent] {}【{}】数据完整性被破坏，数据有被篡改风险", name, cipher);
				};
				value = smData;
			}		
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			log.info(name+" 解密失败: ", e.getMessage());
			throw new BaseException("database--sm4 descrypt error");
		}
		return value;	
	}
}